#ifndef MMAPADAPTER_HPP_
#define MMAPADAPTER_HPP_

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>

#include "memstorage_exceptions.hpp"
#include <string.h>

#define LOGGING_INFO
#include "logger.h"

using std::string;
class MappableFile {
	public:
	MappableFile(const string& path, size_t size, size_t page_size)
		: 	path_(path), 
			size_(size), 
			page_size_(page_size)
	{
		fd_ = open(path.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0777);//may be magic nomder?
		if (fd_ < 0) {
			LOG_ERROR("can't create file : <%s>", strerror(errno));
			throw MemAllocException(MemAllocException::E_BADF);
		}
		if (ftruncate(fd_, size_) < 0) {
			LOG_ERROR("can't trunc file : <%s> %d %lu", strerror(errno), fd_, size_);
			throw MemAllocException(MemAllocException::E_BADF);
		}
	}
	
	~MappableFile()
	{
		if (remove(path_.c_str()) < 0) {
			LOG_ERROR("can't remove file : <%s> %d %lu", strerror(errno), fd_, size_);
			throw MemAllocException(MemAllocException::E_BADF);
		}
	}
	
	inline void* memMap(size_t offset)
	{
		void* res = mmap(0, page_size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_, offset);
		if (res == MAP_FAILED) {
			LOG_ERROR("mmap operation failed: <%s>", strerror(errno));
			throw MemAllocException(MemAllocException::E_BADF);
		}
		return res;
	}
	
	inline void memUnmap(void* mem)
	{
		if (munmap(mem, page_size_) < 0) {
			LOG_ERROR("munmap operation failed");
			throw MemAllocException(MemAllocException::E_BADF);
		}
	}

	inline void sync(void* mem)
	{
		if (msync(mem, page_size_, MS_SYNC) < 0) {
			LOG_ERROR("can't sync");
			throw MemAllocException(MemAllocException::E_BADF);
		}
	}
	
	private:
	string path_;
	size_t page_size_;
	int fd_;
	size_t size_;
};


#endif //MMAPADAPTER
